import rdbManager from "../VecDbModel/rdbManager"
import { common } from "@kit.AbilityKit"
import {
  call2taskstep,
  defaultJTaskItem,
  defaultTaskItem,
  funcCall,
  globparam,
  jtaskItem,
  OperMode,
  stepparam,
  taskItem,
  taskstep,
  taskTrack
} from "../utils/taskGraphInterface"
import { promptAction } from "@kit.ArkUI"
import rdb from "@ohos.data.rdb"
import { relationalStore } from "@kit.ArkData"
import { AccessibilityExtensionContext } from "@kit.AccessibilityKit"

let TAG = "taskStorage"

export class taskStorage {
  static dbCreated = false
  context: common.UIAbilityContext | AccessibilityExtensionContext
  static currentCall: funcCall | undefined = undefined
  static firstOperMode: OperMode = OperMode.DOM
  static tracks: taskTrack[] = []

  async pushTrack(track: taskTrack) {
    console.error(TAG, "pushing taskTrack", JSON.stringify(track))
    let jtask = await this.getJTask(taskStorage.currentCall?.functionName)
    if (jtask.steps.length > 0 && taskStorage.tracks.length == 0) {
      console.error(TAG, "about to delete existing steps in jtask", jtask.name, JSON.stringify(jtask.steps))
      jtask.steps = []
    }
    taskStorage.tracks.push(track)
    jtask.steps.push(call2taskstep(track.call))
    await this.updateJTask(jtask)
  }

  constructor(context: common.UIAbilityContext | AccessibilityExtensionContext | undefined = undefined) {
    if (context != undefined) {
      this.context = context
      this.createDb()
    }
  }

  async createDb() {
    let TAG = "_:create_DB"
    console.log(TAG, "entered")
    if (!taskStorage.dbCreated) {
      try {
        taskStorage.dbCreated = true
        await rdbManager.createStore(this.context)
        console.log(TAG, "store created")
        await rdbManager.createTable("tasks",
          "(id integer primary key autoincrement,name string,task string,steps string,gparams string,historycalls string)")
        console.log(TAG, "table created: tasks")
        await this.initializeTasks()
      } catch (e) {
        console.error(TAG, "error", JSON.stringify(e))
        taskStorage.dbCreated = false
      }
    } else {
      return
    }
  }

  async initializeTasks() {
    let TAG = "_:initializeTasks"
    console.log(TAG, "entered")
    let gParams: globparam[] =
      [{ key: "text", value: "" }, { key: "direction", value: "" }]
    let TaskSteps: taskstep[]
    this.insertTask({
      name: "scrollclick",
      gparams: JSON.stringify(gParams),
      steps: JSON.stringify([]),
      task: "在一个可能可被滚动的页面中，自动滚动并查找与$text相同或包含$text的文本元素，并对其点击。\ndirection:'vf'|'vb'|'hf'|'hb'。h代表横向,v代表纵向,f:forward代表向xy坐标和增大的地方翻,b:backward减小",
      historycalls: JSON.stringify([])
    })
    gParams =
      [{ key: "text", value: "" }, { key: "hintText", value: "" }]
    this.insertTask({
      name: "type",
      gparams: JSON.stringify(gParams),
      steps: JSON.stringify([]),
      task: "在屏幕中找到占位提示文字为$hintText文本输入框,并输入$text",
      historycalls: JSON.stringify([{
        task: "type搜索",
        functionName: "type",
        gparams: [{ key: "text", value: "test" }, { key: "hintText", value: "搜索" }]
      },
        {
          task: "type姓名",
          functionName: "type",
          gparams: [{ key: "text", value: "test" }, { key: "hintText", value: "姓名" }]
        },
        {
          task: "type电话",
          functionName: "type",
          gparams: [{ key: "text", value: "1234" }, { key: "hintText", value: "电话" }]
        }])
    })
    //如果已知输入框的坐标，则$hintText填''，转而填$xPos和$yPos
    this.insertTask({
      name: "backHome",
      gparams: JSON.stringify([]),
      steps: JSON.stringify([]),
      task: "回到桌面（没有参数，可以在两个独立子任务间使用）",
      historycalls: JSON.stringify([])
    })
    this.insertTask({
      name: "back",
      gparams: JSON.stringify([]),
      steps: JSON.stringify([]),
      task: "返回按钮",
      historycalls: JSON.stringify([])
    })
    this.insertTask({
      name: "click",
      gparams: JSON.stringify([{ key: "x", value: "0" }, { key: "y", value: "0" }, { key: "text", value: "" }]),
      steps: JSON.stringify([]),
      task: "点击屏幕指定坐标($X,$y)或指定文字$text。如果x>0&&y>0则点击坐标，否则点击屏幕上文字$text的位置",
      historycalls: JSON.stringify([])
    })
    this.insertTask({
      name: "scroll",
      gparams: JSON.stringify([{ key: "startX", value: "0" }, { key: "startY", value: "0" },
        { key: "dir", value: "vf" }]),
      steps: JSON.stringify([]),
      task: "点击屏幕指定坐标",
      historycalls: JSON.stringify([])
    })
    gParams = []
    this.insertTask({
      name: "keyCode",
      gparams: JSON.stringify([{ key: "code", value: "2" }]),
      steps: JSON.stringify([]),
      task: "注入keyCode",
      historycalls: JSON.stringify([])
    })
    // TaskSteps = [{
    //   functionName: "scrollclick",
    //   stepparams: [{ key: "text", value: "", globalkey: "" }]
    // }, {
    //   functionName: "type",
    //   stepparams: [{ key: "text", value: "", globalkey: "" }]
    // }]
    // this.insertTask({
    //   name: "search_accessibility",
    //   gparams: JSON.stringify(gParams),
    //   steps: JSON.stringify(TaskSteps),
    //   task: "在桌面上scrollclick翻找到并点击打开应用‘设置’，然后在‘搜索’输入框中type输入accessibility",
    //   historycalls: JSON.stringify([])
    // })

    // gParams = [{ key: "search1", value: "string" }, { key: "search2", value: "kika" }]
    // TaskSteps = [{ functionName: "search_accessibility", stepparams: sParams }]
    // this.insertTask({
    //   name: "searchSettings",
    //   gparams: JSON.stringify(gParams),
    //   steps: JSON.stringify(TaskSteps),
    //   task: "",
    //   historycalls: JSON.stringify([])
    // })
  }


  async getAllTasks(): Promise<taskItem[]> {
    let TAG = "_:getAllTasks"
    console.log(TAG, "entered")
    let taskitems: taskItem[] = (await rdbManager.query("tasks")) as taskItem[]
    return taskitems
  }

  findJTask(targetTaskName: string, arr: jtaskItem[]): jtaskItem {
    let jtask = arr.find(jtask => jtask.name == targetTaskName)
    if (jtask == undefined) {
      console.error(TAG, "jtask not found named" + targetTaskName, "AMONG",
        arr.map(jtask => jtask.name))
      jtask = defaultJTaskItem("notDefined", "jtask not found named" + targetTaskName + "AMONG" +
      arr.map(jtask => jtask.name))
    }
    return jtask
  }

  async getJTask(targetTaskName: string): Promise<jtaskItem> {
    let TAG = "_:getTask"
    console.log(TAG, "entered", targetTaskName)
    let taskitems: taskItem[] = await this.getAllTasks()
    let foundTask: taskItem | undefined
    foundTask = taskitems.find((task: taskItem) => {
      return task.name == targetTaskName
    })
    if (foundTask != undefined) {
      return this.getJTaskByTask(foundTask)
    } else {
      // promptAction.showToast({
      //   message: "failed to getTask cur= " + taskStorage.currentCall?.functionName + "\n among" +
      //   taskitems.map(task => task.name)
      // })
      console.error(TAG,
        "failed to getTask cur=" + taskStorage.currentCall?.functionName + "among" + taskitems.map(task => task.name))
      return defaultJTaskItem("notDefined",
        "getJTask not found task named" + targetTaskName + "\namong" + taskitems.map(task => task.name))
    }
  }

  async deleteTask(taskName: string) {
    let predicates = new relationalStore.RdbPredicates("tasks");
    predicates.equalTo("name", taskName);
    await rdbManager.deleteTableItem(predicates)
  }

  async getAllJTasks() {
    let tasks: taskItem[] = await this.getAllTasks()
    let para: Promise<jtaskItem>[] = tasks.map((task) => {
      return this.getJTask(task.name)
    })
    let Jtasks: jtaskItem[] = await Promise.all(para)
    return Jtasks
  }

  getJTaskByTask(foundTask: taskItem): jtaskItem {
    let jtask: jtaskItem | undefined
    if (foundTask.historycalls == "" || foundTask.gparams == "" || foundTask.steps == "") {
      promptAction.showToast({
        message: "taskItem.historycalls gparams steps can not be initiallized with '' because it will cause JSON.stringify error"
      })
      console.error("_:_code error taskItem.historycalls gparams steps can not be initiallized with '' because it will cause JSON.stringify error")
      console.error("_:_code error historycalls", foundTask.historycalls, "gparams", foundTask.gparams,
        "steps", foundTask.steps)
      if (foundTask.historycalls == "") {
        foundTask.historycalls = JSON.stringify([])
      }
      if (foundTask.gparams == "") {
        foundTask.gparams = JSON.stringify([])
      }
      if (foundTask.steps == "") {
        foundTask.steps = JSON.stringify([])
      }
    }
    try {
      jtask = {
        name: foundTask.name,
        task: foundTask.task,
        steps: (JSON.parse(foundTask.steps) as taskstep[]),
        gparams: (JSON.parse(foundTask.gparams) as globparam[]),
        historycalls: (JSON.parse(foundTask.historycalls) as funcCall[])
      }
      console.warn(TAG, "got task for currentpage", JSON.stringify(jtask))
    } catch (e) {
      console.error(TAG, "parse failed", e, JSON.stringify(e))
      jtask = defaultJTaskItem("notDefined",
        "getJTaskByTask,from parsing error:" + e + "\noriginal:" + JSON.stringify(foundTask))
    }
    return jtask
  }

  async insertTask(taskitem: taskItem) {
    let alltasks = await this.getAllTasks()
    if (alltasks.find(task => task.name == taskitem.name)) {
      // promptAction.showToast({ message: "已有同名任务" + taskitem.name })
      return
    }
    let TAG = "_:_insertTask"
    console.log(TAG, "entered")
    await rdbManager.insert("tasks", taskitem)
  }

  async insertJTask(jtaskitem: jtaskItem) {
    let alltasks = await this.getAllTasks()
    if (alltasks.find(task => task.name == jtaskitem.name)) {
      // promptAction.showToast({ message: "已有同名任务" + jtaskitem.name })
      return
    }
    let TAG = "_:_insertJTask"
    console.log(TAG, "entered")
    let taskitem: taskItem = {
      task: jtaskitem.task,
      name: jtaskitem.name,
      steps: JSON.stringify(jtaskitem.steps),
      gparams: JSON.stringify(jtaskitem.gparams),
      historycalls: JSON.stringify(jtaskitem.historycalls)
    }
    await rdbManager.insert("tasks", taskitem)
  }

  async updateJTask(taskitem: jtaskItem) {
    try {
      let strtaskitem: taskItem = {
        name: taskitem.name,
        task: taskitem.task,
        steps: JSON.stringify(taskitem.steps),
        gparams: JSON.stringify(taskitem.gparams),
        historycalls: JSON.stringify(taskitem.historycalls),
      }
      let TAG = "_:_updateJTask"
      console.log(TAG, "entered", JSON.stringify(taskitem))
      let predicates = new relationalStore.RdbPredicates("tasks");
      predicates.equalTo("name", strtaskitem.name);
      await rdbManager.update(strtaskitem, predicates)
    } catch (e) {
      console.error("_:_updateJTask error", JSON.stringify(taskitem))
    }
  }

  mergegparam(originalPs: globparam[], addps: globparam[]) {
    let TAG = "_:_mergegparam"
    let origps = JSON.parse(JSON.stringify(originalPs)) as globparam[]
    origps.map((op) => {
      let founda = addps.find(ap => ap.key == op.key)
      if (founda) {
        op.value = founda.value
      } else {
        promptAction.showToast({
          message: "LLM giving params not existed in the old function" + JSON.stringify(originalPs)
        ,
          duration: 5000
        })
        console.error(TAG, "LLM giving params not existed in the old function" + JSON.stringify(originalPs))
      }
    })
    return origps
  }
}